'use strict';
const Service = require('egg').Service;
const WebSocketServer = require('ws').Server;

// 公网websocket服务
class websocketServer extends Service {
  start(query) {
    const app = this.app;
    const ctx = this.ctx;
    const ws = new WebSocketServer({
      port: query.port,
    });

    ws.on('connection', async (connection, req) => {
      // peer_id=928112&type=app
      const params = new Map();
      if (req.url && req.url.length > 0) {
        const arr = req.url.substring(2).split('&');
        if (arr && arr.length > 0) {
          arr.forEach((value, index, array) => {
            if (value && value.includes('=')) {
              const arr2 = value.split('=');
              params.set(arr2[0], arr2[1]);
            }
          });
        }
      }
      const peer_id = parseInt(params.has('peer_id') ? params.get('peer_id') : '');
      const type = params.has('type') ? params.get('type') : '';
      console.log('已连接', type, peer_id);
      const timestamp = new Date().getTime();
      let user_id = null;
      if (type == 'app') {
        console.log('user-Id', params);
        user_id = params.has('user_id') ? params.get('user_id') : '';
        if (await app.redis.exists(user_id)) {
          // 已有人登录
          const info = JSON.parse((await app.redis.get(user_id)) || []);
          if (info.timestamp != timestamp) {
            const connect = app.wsClients.get(parseInt(info.peer_id));
            // 通知下线
            if (connect) {
              console.log('通知下线');
              connect.send(
                JSON.stringify({
                  type: 1000,
                  sub_type: 1000,
                })
              );
            }
          }
        }
        // 无人登录
        await app.redis.set(
          user_id,
          JSON.stringify({
            peer_id,
            timestamp,
          })
        );
      }
      // 1. 缓存连接
      app.wsClients.set(peer_id, connection);
      ctx.logger.info('perr_id上线', peer_id);
      // 推送ws连接列表至所有用户
      ctx.helper.sendToConnect('all', {
        type: 500,
        sub_type: 506,
        data: {
          wsClients: [...app.wsClients.keys()],
        },
      });
      // 2. 启动心跳
      this.heartCheck(peer_id);
      connection.on('message', async e => {
        // 解析
        let message = {};
        try {
          message = JSON.parse(e);
        } catch (e) {
          console.log('receive message error:', e);
        }
        // 响应心跳
        if (message.event == 'ping') {
          try {
            connection.send(
              JSON.stringify({
                event: 'pong',
              })
            );
          } catch (e) {
            ctx.logger.info('当前连接出现异常');
          }
          return;
        }
        if (message.event == 'pong') {
          this.clearHandleTimeout(peer_id);
          return;
        }
        console.log('收到websocket消息', message.type);
        ctx.helper.handleWebsocketMessage(message, connection, type);
      });

      // 连接后，出现错误
      connection.on('error', error => {
        ctx.logger.info('websocket server error =>', error);
      });

      // 关闭
      connection.on('close', async (code, reason) => {
        if (type == 'app' && (await app.redis.exists(user_id))) {
          ctx.logger.info('用户信息', await app.redis.get(user_id));
          const info = JSON.parse((await app.redis.get(user_id)) || {});
          console.log('离线');
          if (info.timestamp == timestamp) {
            console.log('离线删除');
            await app.redis.del(user_id);
          }
        }
        app.wsClients.forEach((value, key) => {
          if (key == peer_id) {
            ctx.logger.info('delete user:', key);
            this.handleWsException(key);
          }
        });
      });
    });
  }

  // websocket 心跳
  heartCheck(peer_id) {
    const timeout = 8 * 1000;
    const app = this.app;
    const keepTimeOut = setTimeout(() => {
      if (app.wsClients.has(peer_id)) {
        const con = app.wsClients.get(peer_id);
        con.send(
          JSON.stringify({
            event: 'ping',
          })
        );
        const handleTimeout = setTimeout(() => {
          this.ctx.logger.info('【timeout触发】有客户端或者子服务离线，peer_id为 => ', peer_id);
          this.handleWsException(peer_id);
        }, 15 * 1000);
        // 离线map
        app.outLineTimeout.set(peer_id, handleTimeout);

        this.heartCheck(peer_id);
      }
    }, timeout);
    // 心跳map
    app.wsAliveClients.set(peer_id, keepTimeOut);
  }

  clearHandleTimeout(peer_id) {
    const app = this.app;
    // 清除定时器
    clearTimeout(app.outLineTimeout.get(peer_id));
    app.outLineTimeout.delete(peer_id);
  }

  async handleWsException(peer_id) {
    const app = this.app;
    const ctx = this.ctx;
    // 1. 清除连接
    if (app.wsClients.get(peer_id)) {
      app.wsClients.get(peer_id).close();
    }
    app.wsClients.delete(peer_id);

    // 设备离线修改为srs协议
    const list = await this.ctx.model.Device.findAndCountAll({
      where: {
        video_box_id: parseInt(peer_id),
      },
      raw: true,
    });
    list.rows.forEach(v => {
      this.ctx.service.device.update({
        id: v.id,
        video_box_ip: null,
      });
    });
    // 推送ws连接列表至所有用户
    ctx.helper.sendToConnect('all', {
      type: 500,
      sub_type: 506,
      data: {
        wsClients: [...app.wsClients.keys()],
      },
    });
    // 发送
    // 2. 清除心跳
    clearTimeout(app.wsAliveClients.get(peer_id));
    app.wsAliveClients.delete(peer_id);

    // 3. 清除离线
    clearTimeout(app.outLineTimeout.get(peer_id));
    app.outLineTimeout.delete(peer_id);
  }

  // 更新设备告警状态
  updateDeviceAlarm(peer_id) {
    this.ctx.model.Alarm.update(
      {
        resource_id: peer_id,
        status: 1,
      },
      {
        where: {
          resource_id: peer_id,
        },
      }
    ).catch(err => {
      this.ctx.logger.error('更新子服务告警状态失败 =>', err);
    });
  }
}
module.exports = websocketServer;
